/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#include "BackintConst.h"
#include <string>
#include <cstdio>
#include <iostream>
#include <vector>
#include <cstring>
#include <fstream>
#ifdef WIN32
#include <windows.h>
#else
#include <dirent.h>
#include <unistd.h>
#endif
#include <sstream>
#include "json/json.h"
#include "common/File.h"
#include "common/MpString.h"
#include "common/JsonUtils.h"
#include "common/JsonHelper.h"

namespace backint {
const std::string DB_INFO_FILE = "dbinfo.txt";
const uint32_t PIPE_OR_FILE_INDEX = 1;
const uint32_t INPUT_FILE_INDEX = 1;
const uint32_t EBID_INPUT_FILE_INDEX = 2;
const uint32_t DB_NAME_INDEX = 1;
const uint32_t MIN_INPUT_FILE_LINES = 2;
const uint32_t INPUT_FILE_TITLE_LINE = 0;
const uint32_t VERSION_INDEX = 2;
const uint32_t NAME_PATH_MAX = 512;
const uint32_t FILE_PATH_MAX = 512;

uint32_t GetCpuNum()
{
    SYSTEM_INFO sysInfo;
    GetSystemInfo(&sysInfo);
    INFOLOG("System cpu num: %d", sysInfo.dwNumberOfProcessors);
    return sysInfo.dwNumberOfProcessors;
}

std::string GetAgentHome()
{
    char *value = nullptr;
    size_t size = 0;
    std::string agentHome;
    if (_dupenv_s(&value, &size, "DATA_BACKUP_AGENT_HOME") == 0 && value != nullptr) {
        agentHome = std::string(value);
        free(value);
        value = nullptr;
    }
    INFOLOG("Agent home: %s", agentHome.c_str());
    return agentHome;
}

int SafeStoi(const std::string &key)
{
    int value = -1;
    try {
        value = std::stoi(key);
    } catch (...) {
        value = -1;
    }
    return value;
}

void ParseLogFile(const std::string &filePath, int &loglevel, int &logCount, int &logMaxSize)
{
    if (filePath.empty()) {
        return;
    }
    std::ifstream iniFile(filePath);
    if (!iniFile.is_open()) {
        return;
    }
    std::string line;
    while (std::getline(iniFile, line)) {
        if (line.empty()) {
            continue;
        }
        if (!(line.find("LogLevel=") != std::string::npos || line.find("LogCount=") != std::string::npos ||
                line.find("LogMaxSize=") != std::string::npos)) {
            continue;
        }

        size_t npos = line.find('=');
        std::string key = line.substr(0, npos);
        std::string value = line.substr(npos + 1);
        if (key == "LogLevel") {
            loglevel = SafeStoi(value);
        } else if (key == "LogCount") {
            logCount = SafeStoi(value);
        } else {
            logMaxSize = SafeStoi(value);
        }
    }
    iniFile.close();
}

int GetBackupList(const std::string &filePath, StuFileInfo &stFileInfo)
{
    LOGGUARD("");
    std::ifstream pipe(filePath);
    if (!pipe.is_open()) {
        ERRLOG("file open failed: %s", filePath.c_str());
        return FAILED;
    }
    std::string data;
    while (std::getline(pipe, data)) {
        std::string strData = data;
        if (!strData.empty()) {
            StuFileData stuFileData;
            stuFileData.m_filePath = strData;
            stFileInfo.fileData.push_back(stuFileData);
        }
    }
    return SUCCESS;
}

uint32_t ParsePluginParams(const std::string &paramFile, PlugParams &plugParams)
{
    LOGGUARD("");
    Json::Value jsonValue;
    std::string paramString;

    if (Module::CFile::ReadFile(paramFile, paramString) != SUCCESS) {
        ERRLOG("Failed to open file");
        return FAILED;
    }
    if (!Module::JsonHelper::JsonStringToJsonValue(paramString, jsonValue)) {
        ERRLOG("Failed to convert string to json");
        return FAILED;
    }
    Module::CJsonUtils::GetJsonString(jsonValue, "pid", plugParams.m_pid);
    Module::CJsonUtils::GetJsonString(jsonValue, "job_id", plugParams.m_jobId);
    Module::CJsonUtils::GetJsonString(jsonValue, "sub_job_id", plugParams.m_subJobId);
    Module::CJsonUtils::GetJsonString(jsonValue, "db_name", plugParams.m_dbName);
    Module::CJsonUtils::GetJsonString(jsonValue, "data_path", plugParams.m_dataPath);
    Module::CJsonUtils::GetJsonString(jsonValue, "cache_path", plugParams.m_cachePath);
    Module::CJsonUtils::GetJsonString(jsonValue, "meta_path", plugParams.m_metaPath);
    Module::CJsonUtils::GetJsonInt32(jsonValue, "parallel", plugParams.m_channels);
    return SUCCESS;
}

uint32_t GetInFilePath(int argc, char **argv, std::string &filePath)
{
    std::string regs = "-i";
    for (auto i = 0; i < argc; ++i) {
        if (regs.compare(argv[i]) == SUCCESS && (argc > i + 1)) {
            filePath = argv[i + 1];
            return SUCCESS;
        }
    }
    ERRLOG("Failed to get infile path.");
    return FAILED;
}

uint32_t WriteOutFile(const std::vector<std::string> &result, const std::string &outFile)
{
    if (outFile.empty()) {
        return SUCCESS;
    }
    std::ofstream outfile(outFile, std::ios::app);
    if (!outfile.is_open()) {
        ERRLOG("Failed to open file: %s, errno: %d.", outFile.c_str(), errno);
        return FAILED;
    }
    for (const auto &line : result) {
        outfile << line << " ";
    }
    outfile << "\n";
    outfile.close();
    return SUCCESS;
}

std::string GetFileName(const std::string &filePath)
{
    size_t pos = filePath.find_last_of(PATH_SEP_CHAR);
    if (pos == std::string::npos) {
        return filePath;
    }
    return filePath.substr(pos + 1);
}

void FindAnfSuffixFiles(const std::string &dataPath, std::vector<std::string> &files)
{
    const int sizeAnfSuff = 4;
    std::string searchPath = dataPath + "\\*";
    WIN32_FIND_DATA findData;
    HANDLE hFind = FindFirstFile(searchPath.c_str(), &findData);
    if (hFind == INVALID_HANDLE_VALUE) {
        return;
    }
    do {
        if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            if (strcmp(findData.cFileName, ".") != 0 && strcmp(findData.cFileName, "..") != 0) {
                FindAnfSuffixFiles(dataPath + "\\" + findData.cFileName, files);
            }
        } else {
            std::string fileName = findData.cFileName;
            if (fileName.size() >= sizeAnfSuff &&
                fileName.compare(fileName.size() - sizeAnfSuff, sizeAnfSuff, ".anf") == 0) {
                files.push_back(dataPath + "\\" + fileName);
            }
        }
    } while (FindNextFile(hFind, &findData) != 0);
    FindClose(hFind);
}

}  // namespace backint